home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_3 / multiuser / src / library / server.c < prev    next >
C/C++ Source or Header  |  1994-06-29  |  18KB  |  784 lines

  1. /************************************************************
  2. * MultiUser - MultiUser Task/File Support System                *
  3. * ---------------------------------------------------------    *
  4. * Server Process                                                            *
  5. * ---------------------------------------------------------    *
  6. * © Copyright 1993-1994 Geert Uytterhoeven                        *
  7. * All Rights Reserved.                                                    *
  8. ************************************************************/
  9.  
  10.  
  11. #include <exec/execbase.h>
  12. #include <exec/alerts.h>
  13. #include <exec/ports.h>
  14. #include <dos/dos.h>
  15. #include <dos/dostags.h>
  16. #include <utility/tagitem.h>
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/utility.h>
  20. #include <proto/reqtools.h>
  21. #include <libraries/reqtools.h>
  22. #include <string.h>
  23.  
  24. #include "Memory.h"
  25. #include "Server.h"
  26. #include "Config.h"
  27. #include "Locale.h"
  28. #include "LibHeader.h"
  29. #include "Misc.h"
  30. #include "Task.h"
  31. #include "UserInfo.h"
  32. #include "GroupInfo.h"
  33. #include "Monitor.h"
  34.  
  35.  
  36.     /*
  37.      *        Static Routines
  38.      */
  39.  
  40. static void __saveds ServerProcess(void);
  41. static struct muPrivUserInfo *CheckUser(ULONG user, STRPTR userid, STRPTR pwd, BOOL nopasswd,
  42.                                                      BOOL nolog);
  43. static BOOL Passwd(ULONG user, STRPTR oldpwd, STRPTR newpwd);
  44. static struct muPrivUserInfo *GetUserInfo(struct muPrivUserInfo *info, ULONG keytype);
  45. static BOOL Belongs2(struct muUserDef *def, UWORD gid);
  46. static void FillUserInfo(struct muUserDef *def, struct muPrivUserInfo *info);
  47. static BOOL CheckPasswd(ULONG user, STRPTR pwd);
  48. static struct muPrivGroupInfo *GetGroupInfo(struct muPrivGroupInfo *info, ULONG keytype);
  49. static void FillGroupInfo(struct muGroupDef *def, struct muPrivGroupInfo *info);
  50.  
  51.  
  52.     /*
  53.      *        Configuration Stuff
  54.      */
  55.  
  56. extern BPTR PasswdDirLock;
  57. extern BPTR ConfigDirLock;
  58.  
  59.  
  60.     /*
  61.      *        Start the Server's Process
  62.      */
  63.  
  64. struct Process *CreateServer(void)
  65. {
  66.     static struct TagItem tags[] = {
  67.         NP_Entry, (LONG)ServerProcess,
  68.         NP_Name, (LONG)SERVERNAME,
  69.         NP_Priority, SERVERPRI,
  70.         NP_StackSize, SERVERSTACK,
  71.         TAG_DONE
  72.     };
  73.  
  74.     return(muBase->Server = CreateNewProc((struct TagItem *)tags));
  75.  
  76. }
  77.  
  78.  
  79.     /*
  80.      *        Activate the Server by sending the Startup Message
  81.      */
  82.  
  83. BOOL StartServer(void)
  84. {
  85.     return((BOOL)DoPkt(&muBase->Server->pr_MsgPort, ACTION_STARTUP, NULL, NULL, NULL, NULL, NULL));
  86. }
  87.  
  88.  
  89.     /*
  90.      *        Kill the Server
  91.      */
  92.  
  93. BOOL KillServer(void)
  94. {
  95.     return((BOOL)SendServerPacket(muSAction_Quit, NULL, NULL, NULL, NULL));
  96. }
  97.  
  98.  
  99.     /*
  100.      *        Send a Packet to the Server
  101.      */
  102.  
  103. LONG SendServerPacket(LONG type, LONG arg1, LONG arg2, LONG arg3, LONG arg4)
  104. {
  105.     struct muSPacket pkt;
  106.     struct MsgPort *port;
  107.  
  108.     if (port = CreateMsgPort()) {
  109.  
  110.             /*
  111.              *        Initialise the Server Packet
  112.              */
  113.  
  114.         pkt.Msg.mn_Node.ln_Succ = NULL;
  115.         pkt.Msg.mn_Node.ln_Pred = NULL;
  116.         pkt.Msg.mn_Node.ln_Type = NULL;
  117.         pkt.Msg.mn_Node.ln_Pri = NULL;
  118.         pkt.Msg.mn_Node.ln_Name = NULL;
  119.         pkt.Msg.mn_ReplyPort = port;
  120.         pkt.Msg.mn_Length = sizeof(struct muSPacket);
  121.         pkt.Type = type;
  122.         pkt.Arg1 = arg1;
  123.         pkt.Arg2 = arg2;
  124.         pkt.Arg3 = arg3;
  125.         pkt.Arg4 = arg4;
  126.         pkt.Res1 = NULL;
  127.  
  128.             /*
  129.              *        Transmit the packet and wait for reply
  130.              */
  131.  
  132.         Forbid();
  133.         if (muBase->ServerPort) {
  134.             PutMsg(muBase->ServerPort, (struct Message *)&pkt);
  135.             Permit();
  136.             do
  137.                 WaitPort(port);
  138.             while (GetMsg(port) != (struct Message *)&pkt);
  139.         } else
  140.             Permit();
  141.  
  142.         DeleteMsgPort(port);
  143.         return(pkt.Res1);
  144.     } else
  145.         return(NULL);
  146. }
  147.  
  148.  
  149.     /*
  150.      *        The Server's Process
  151.      */
  152.  
  153. static void __saveds ServerProcess(void)
  154. {
  155.     struct muSPacket *pkt;
  156.     BOOL quit = FALSE;
  157.     ULONG user;
  158.     ULONG signals;
  159.     struct DosPacket *spkt;
  160.  
  161.         /*
  162.          *        Get Startup Message
  163.          */
  164.  
  165.     spkt = WaitPkt();
  166.  
  167.         /*
  168.          *        Do all necessary initialisations
  169.          */
  170.  
  171.     ((struct Process *)SysBase->ThisTask)->pr_WindowPtr = (APTR)-1;
  172.  
  173.     if (((muBase->NotifySig = AllocSignal(-1)) == -1) ||
  174.          ((muBase->ConsistencySig = AllocSignal(-1)) == -1) || !(muBase->ServerPort = CreateMsgPort()) ||
  175.          !(muBase->MonitorPort = CreateMsgPort())) {
  176.         ReplyPkt(spkt, DOSFALSE, NULL);
  177.         Die(NULL, AN_Unknown | AG_NoSignal);
  178.     }
  179.  
  180.         /*
  181.          *        Reply Startup Message
  182.          */
  183.  
  184.     ReplyPkt(spkt, DOSTRUE, NULL);
  185.  
  186.     InitVolumes();
  187.  
  188.     do {
  189.         signals = Wait(1<<muBase->NotifySig | 1<<muBase->ConsistencySig |
  190.                             1<<muBase->ServerPort->mp_SigBit | 1<<muBase->MonitorPort->mp_SigBit);
  191.  
  192.         if (signals & 1<<muBase->NotifySig)
  193.             FreeDefs();
  194.  
  195.         if (signals & 1<<muBase->ConsistencySig) {
  196.             FreeVolumes();
  197.             InitVolumes();
  198.         }
  199.  
  200.         if (signals & 1<<muBase->ServerPort->mp_SigBit)
  201.             while (!quit && (pkt = (struct muSPacket *)GetMsg(muBase->ServerPort))) {
  202.                 switch (pkt->Type) {
  203.                     case muSAction_Quit:
  204.  
  205.                             /*
  206.                              *        Quit
  207.                              *
  208.                              *
  209.                              *        Arg1:    /
  210.                              *        Arg2:    /
  211.                              *        Arg3:    /
  212.                              *
  213.                              *        Res1:    BOOL success
  214.                              */
  215.  
  216.                         quit = TRUE;
  217.                         pkt->Res1 = TRUE;
  218.  
  219.                             /*
  220.                              *        Ensure the Server will be RemTask()ed BEFORE any
  221.                              *        other task will get the processor !!
  222.                              */
  223.  
  224.                         Forbid();
  225.                         break;
  226.  
  227.                     case muSAction_CheckUser:
  228.  
  229.                             /*
  230.                              *        CheckUser
  231.                              *
  232.                              *
  233.                              *        Arg1:    STRPTR uid
  234.                              *        Arg2:    STRPTR pwd
  235.                              *        Arg3:    BOOL nopasswd
  236.                              *
  237.                              *        Res1:    struct muPrivUserInfo *info (NULL for failure)
  238.                              */
  239.  
  240.                         user = GetTaskOwner(pkt->Msg.mn_ReplyPort->mp_SigTask);
  241.                         pkt->Res1 = (LONG)CheckUser(user, (STRPTR)pkt->Arg1, (STRPTR)pkt->Arg2,
  242.                                                              (BOOL)pkt->Arg3, (BOOL)pkt->Arg4);
  243.                         break;
  244.  
  245.                     case muSAction_Passwd:
  246.  
  247.                             /*
  248.                              *        Passwd
  249.                              *
  250.                              *
  251.                              *        Arg1:    STRPTR oldpwd
  252.                              *        Arg2:    STRPTR newpwd
  253.                              *        Arg3:    /
  254.                              *
  255.                              *        Res1:    BOOL success
  256.                              */
  257.  
  258.                         user = GetTaskOwner(pkt->Msg.mn_ReplyPort->mp_SigTask);
  259.                         pkt->Res1 = (LONG)Passwd(user, (STRPTR)pkt->Arg1, (STRPTR)pkt->Arg2);
  260.                         break;
  261.  
  262.                     case muSAction_GetUserInfo:
  263.  
  264.                             /*
  265.                              *        GetUserInfo
  266.                              *
  267.                              *
  268.                              *        Arg1:    struct muPrivUserInfo *info
  269.                              *        Arg2:    ULONG keytype
  270.                              *        Arg3:    /
  271.                              *
  272.                              *        Res1:    struct muPrivUserInfo *info (NULL for failure)
  273.                              */
  274.  
  275.                         pkt->Res1 = (LONG)GetUserInfo((struct muPrivUserInfo *)pkt->Arg1, (ULONG)pkt->Arg2);
  276.                         break;
  277.  
  278.                     case muSAction_CheckPasswd:
  279.  
  280.                             /*
  281.                              *        CheckPasswd
  282.                              *
  283.                              *
  284.                              *        Arg1:    STRPTR pwd
  285.                              *        Arg2:    /
  286.                              *        Arg3:    /
  287.                              *
  288.                              *        Res1:    BOOL success
  289.                              */
  290.  
  291.                         user = GetTaskOwner(pkt->Msg.mn_ReplyPort->mp_SigTask);
  292.                         pkt->Res1 = (LONG)CheckPasswd(user, (STRPTR)pkt->Arg1);
  293.                         break;
  294.  
  295.                     case muSAction_PasswdDirLock:
  296.  
  297.                             /*        PasswdDirLock
  298.                              *
  299.                              *
  300.                              *        Arg1:    /
  301.                              *        Arg2:    /
  302.                              *        Arg3:    /
  303.                              *
  304.                              *        Res1:    BPTR lock
  305.                              */
  306.  
  307.                         if (PasswdDirLock)
  308.                             pkt->Res1 = DupLock(PasswdDirLock);
  309.                         break;
  310.  
  311.                     case muSAction_ConfigDirLock:
  312.  
  313.                             /*        ConfigDirLock
  314.                              *
  315.                              *
  316.                              *        Arg1:    /
  317.                              *        Arg2:    /
  318.                              *        Arg3:    /
  319.                              *
  320.                              *        Res1:    BPTR lock
  321.                              */
  322.  
  323.                         if (ConfigDirLock)
  324.                             pkt->Res1 = DupLock(ConfigDirLock);
  325.                         break;
  326.  
  327.                     case muSAction_GetGroupInfo:
  328.  
  329.                             /*
  330.                              *        GetGroupInfo
  331.                              *
  332.                              *
  333.                              *        Arg1:    struct muPrivGroupInfo *info
  334.                              *        Arg2:    ULONG keytype
  335.                              *        Arg3:    /
  336.                              *
  337.                              *        Res1:    struct muPrivGroupInfo *info (NULL for failure)
  338.                              */
  339.  
  340.                         pkt->Res1 = (LONG)GetGroupInfo((struct muPrivGroupInfo *)pkt->Arg1, (ULONG)pkt->Arg2);
  341.                         break;
  342.  
  343.                     default:
  344.                         break;
  345.                 }
  346.             ReplyMsg((struct Message *)pkt);
  347.             }
  348.  
  349.         if (signals & 1<<muBase->MonitorPort->mp_SigBit)
  350.             FreeRepliedMonMsg();
  351.  
  352.     } while (!quit);
  353.  
  354.     FreeVolumes();
  355.  
  356.     DeleteMsgPort(muBase->MonitorPort);
  357.     DeleteMsgPort(muBase->ServerPort);
  358.     FreeSignal(muBase->ConsistencySig);
  359.     FreeSignal(muBase->NotifySig);
  360.     muBase->MonitorPort = NULL;
  361.     muBase->ServerPort = NULL;
  362.     muBase->ConsistencySig = NULL;
  363.     muBase->Server = NULL;
  364. }
  365.  
  366.  
  367.     /*
  368.      *        Check if a user is licensed to login
  369.      */
  370.  
  371. static struct muPrivUserInfo *CheckUser(ULONG user, STRPTR userid, STRPTR pwd, BOOL nopasswd,
  372.                                                      BOOL nolog)
  373. {
  374.     BOOL found;
  375.     char buffer[12];
  376.     struct muPrivUserInfo *info = NULL;
  377.     struct muUserDef *def;
  378.     UWORD uid;
  379.  
  380.     uid = user>>16;
  381.  
  382.     if (def = GetUserDefs())
  383.         do
  384.             if ((found = (!strcmp(userid, def->UserID))) && (nopasswd ||
  385.                  (Encrypt(buffer, pwd, def->UserID) && !strcmp(buffer, def->Password))) &&
  386.                   (info = muAllocUserInfo()))
  387.                 FillUserInfo(def, info);
  388.             else
  389.                 def = def->Next;
  390.         while (!found && def);
  391.  
  392.     if (info)
  393.         CallMonitors(muTrgB_Login, uid, info->Pub.uid, userid);
  394.     else
  395.         CallMonitors(muTrgB_LoginFail, uid, NULL, userid);
  396.  
  397.     if (!nolog && ((info && (muBase->Config.LogFlags & muLogF_Login)) ||
  398.                         (!info && (muBase->Config.LogFlags & muLogF_LoginFail)))) {
  399.         LONG args[2];
  400.         args[0] = uid;
  401.         args[1] = (LONG)userid;
  402.         if (info)
  403.             VLogF(GetLogStr(MSG_LOG_LOGIN), args);
  404.         else
  405.             VLogF(GetLogStr(MSG_LOG_LOGINFAIL), args);
  406.     }
  407.  
  408.     return(info);
  409. }
  410.  
  411.  
  412.     /*
  413.      *        Change the Password of a user
  414.      */
  415.  
  416. static BOOL Passwd(ULONG user, STRPTR oldpwd, STRPTR newpwd)
  417. {
  418.     BOOL found;
  419.     BOOL changed = FALSE;
  420.     UWORD uid, gid;
  421.     char buffer[12];
  422.     struct muUserDef *def;
  423.  
  424.     uid = user>>16;
  425.     gid = user&muMASK_GID;
  426.  
  427.     if (((uid >= muBase->Config.PasswduidLevel) || (gid >= muBase->Config.PasswdgidLevel)) &&
  428.          (def = GetUserDefs()))
  429.         do
  430.             if (found = (def->uid == uid))
  431.                 changed = Encrypt(buffer, oldpwd, def->UserID) &&  !strcmp(buffer, def->Password) &&
  432.                              Encrypt(def->Password, newpwd, def->UserID) && UpdateUserDefs();
  433.             else
  434.                 def = def->Next;
  435.         while (!found && def);
  436.  
  437.     if (changed)
  438.         CallMonitors(muTrgB_Passwd, uid, NULL, NULL);
  439.     else
  440.         CallMonitors(muTrgB_PasswdFail, uid, NULL, NULL);
  441.  
  442.     if ((changed && (muBase->Config.LogFlags & muLogF_Passwd)) ||
  443.          (!changed && (muBase->Config.LogFlags & muLogF_PasswdFail))) {
  444.         LONG args[1];
  445.         args[0] = uid;
  446.         if (changed)
  447.             VLogF(GetLogStr(MSG_LOG_PASSWD), args);
  448.         else
  449.             VLogF(GetLogStr(MSG_LOG_PASSWDFAIL), args);
  450.     }
  451.  
  452.     return(changed);
  453. }
  454.  
  455.  
  456.     /*
  457.      *        Get Information about a User
  458.      */
  459.  
  460. static struct muPrivUserInfo *GetUserInfo(struct muPrivUserInfo *info, ULONG keytype)
  461. {
  462.     struct muUserDef *def;
  463.     ULONG len;
  464.     ULONG count = 0;
  465.  
  466.     if (def = GetUserDefs()) {
  467.         switch (keytype) {
  468.             case muKeyType_First:
  469.                 break;
  470.  
  471.             case muKeyType_Next:
  472.                 while ((count <= info->Count) && (def = def->Next))
  473.                     count++;
  474.                 break;
  475.  
  476.             case muKeyType_UserID:
  477.                 while (strcmp(def->UserID, info->Pub.UserID) && (def = def->Next))
  478.                     count++;
  479.                 break;
  480.  
  481.             case muKeyType_uid:
  482.                 while ((def->uid != info->Pub.uid) && (def = def->Next))
  483.                     count++;
  484.                 break;
  485.  
  486.             case muKeyType_gid:
  487.                 info->Tgid = info->Pub.gid;
  488.                 while (!Belongs2(def, info->Tgid) && (def = def->Next))
  489.                     count++;
  490.                 break;
  491.  
  492.             case muKeyType_gidNext:
  493.                 while ((count <= info->Count) && (def = def->Next))
  494.                     count++;
  495.                 if (def)
  496.                     while (!Belongs2(def, info->Tgid) && (def = def->Next))
  497.                         count++;
  498.                 break;
  499.  
  500.             case muKeyType_UserName:
  501.                 while (stricmp(def->UserName, info->Pub.UserName) && (def = def->Next))
  502.                     count++;
  503.                 break;
  504.  
  505.             case muKeyType_WUserID:
  506.                 FreeV(info->Pattern);
  507.                 len = 2*strlen(info->Pub.UserID)+2;
  508.                 if ((info->Pattern = MAllocV(len)) &&
  509.                      (ParsePatternNoCase(info->Pub.UserID, info->Pattern, len) != -1))
  510.                     while (!MatchPatternNoCase(info->Pattern, def->UserID) && (def = def->Next))
  511.                         count++;
  512.                 else {
  513.                     FreeV(info->Pattern);
  514.                     info->Pattern = NULL;
  515.                     def = NULL;
  516.                 }
  517.                 break;
  518.  
  519.             case muKeyType_WUserIDNext:
  520.                 if (info->Pattern) {
  521.                     while ((count <= info->Count) && (def = def->Next))
  522.                         count++;
  523.                     if (def)
  524.                         while (!MatchPatternNoCase(info->Pattern, def->UserID) && (def = def->Next))
  525.                             count++;
  526.                 } else
  527.                     def = NULL;
  528.                 break;
  529.  
  530.             case muKeyType_WUserName:
  531.                 FreeV(info->Pattern);
  532.                 len = 2*strlen(info->Pub.UserName)+2;
  533.                 if ((info->Pattern = MAllocV(len)) &&
  534.                      (ParsePatternNoCase(info->Pub.UserName, info->Pattern, len) != -1))
  535.                     while (!MatchPatternNoCase(info->Pattern, def->UserName) && (def = def->Next))
  536.                         count++;
  537.                 else {
  538.                     FreeV(info->Pattern);
  539.                     info->Pattern = NULL;
  540.                     def = NULL;
  541.                 }
  542.                 break;
  543.  
  544.             case muKeyType_WUserNameNext:
  545.                 if (info->Pattern) {
  546.                     while ((count <= info->Count) && (def = def->Next))
  547.                         count++;
  548.                     if (def)
  549.                         while (!MatchPatternNoCase(info->Pattern, def->UserName) && (def = def->Next))
  550.                             count++;
  551.                 } else
  552.                     def = NULL;
  553.                 break;
  554.  
  555.             default:
  556.                 def = NULL;
  557.                 break;
  558.         }
  559.         if (def) {
  560.             FillUserInfo(def, info);
  561.             info->Count = count;
  562.         } else
  563.             info = NULL;
  564.     } else
  565.         info = NULL;
  566.  
  567.     return(info);
  568. }
  569.  
  570.  
  571.     /*
  572.      *        Checker whether a user belongs to a group
  573.      */
  574.  
  575. static BOOL Belongs2(struct muUserDef *def, UWORD gid)
  576. {
  577.     int i;
  578.  
  579.     if (def->gid == gid)
  580.         return(TRUE);
  581.     for (i = 0; i < def->NumSecGroups; i++)
  582.         if (def->SecGroups[i] == gid)
  583.             return(TRUE);
  584.     return(FALSE);
  585. }
  586.  
  587.  
  588.     /*
  589.      *        Fill in the User Information
  590.      */
  591.  
  592. static void FillUserInfo(struct muUserDef *def, struct muPrivUserInfo *info)
  593. {
  594.     strncpy(info->Pub.UserID, def->UserID, muUSERIDSIZE-1);
  595.     info->Pub.UserID[muUSERIDSIZE-1] = '\0';
  596.     info->Pub.uid = def->uid;
  597.     info->Pub.gid = def->gid;
  598.     strncpy(info->Pub.UserName, def->UserName, muUSERNAMESIZE-1);
  599.     info->Pub.UserName[muUSERNAMESIZE-1] = '\0';
  600.     strncpy(info->Pub.HomeDir, def->HomeDir, muHOMEDIRSIZE-1);
  601.     info->Pub.HomeDir[muHOMEDIRSIZE-1] = '\0';
  602.     if (info->Pub.NumSecGroups)
  603.        Free(info->Pub.SecGroups, info->Pub.NumSecGroups*sizeof(UWORD));
  604.     if (def->NumSecGroups && (info->Pub.SecGroups = MAlloc(def->NumSecGroups*sizeof(UWORD)))) {
  605.         info->Pub.NumSecGroups = def->NumSecGroups;
  606.         CopyMem(def->SecGroups, info->Pub.SecGroups, def->NumSecGroups*sizeof(UWORD));
  607.     } else {
  608.         info->Pub.NumSecGroups = 0;
  609.         info->Pub.SecGroups = NULL;
  610.     }
  611.     strncpy(info->Pub.Shell, def->Shell, muSHELLSIZE-1);
  612.     info->Password = !!strlen(def->Password);
  613. }
  614.  
  615.  
  616.     /*
  617.      *        Check the Password of a User
  618.      */
  619.  
  620. static BOOL CheckPasswd(ULONG user, STRPTR pwd)
  621. {
  622.     BOOL found;
  623.     BOOL valid = FALSE;
  624.     UWORD uid;
  625.     char buffer[12];
  626.     struct muUserDef *def;
  627.  
  628.     uid = user>>16;
  629.  
  630.     if (def = GetUserDefs())
  631.         do
  632.             if (found = (def->uid == uid))
  633.                 valid = Encrypt(buffer, pwd, def->UserID) && !strcmp(buffer, def->Password);
  634.             else
  635.                 def = def->Next;
  636.         while (!found && def);
  637.  
  638.     if (valid)
  639.         CallMonitors(muTrgB_CheckPasswd, uid, NULL, NULL);
  640.     else
  641.         CallMonitors(muTrgB_CheckPasswdFail, uid, NULL, NULL);
  642.  
  643.     if ((valid && (muBase->Config.LogFlags & muLogF_CheckPasswd)) ||
  644.          (!valid && (muBase->Config.LogFlags & muLogF_CheckPasswdFail))) {
  645.         LONG args[1];
  646.         args[0] = uid;
  647.         if (valid)
  648.             VLogF(GetLogStr(MSG_LOG_CHECKPASSWD), args);
  649.         else
  650.             VLogF(GetLogStr(MSG_LOG_CHECKPASSWDFAIL), args);
  651.     }
  652.  
  653.     return(valid);
  654. }
  655.  
  656.  
  657.     /*
  658.      *        Get Information about a Group
  659.      */
  660.  
  661. static struct muPrivGroupInfo *GetGroupInfo(struct muPrivGroupInfo *info, ULONG keytype)
  662. {
  663.     struct muGroupDef *def;
  664.     ULONG len;
  665.     ULONG count = 0;
  666.  
  667.     if (def = GetGroupDefs()) {
  668.         switch (keytype) {
  669.             case muKeyType_First:
  670.                 break;
  671.  
  672.             case muKeyType_Next:
  673.                 while ((count <= info->Count) && (def = def->Next))
  674.                     count++;
  675.                 break;
  676.  
  677.             case muKeyType_GroupID:
  678.                 while (strcmp(def->GroupID, info->Pub.GroupID) && (def = def->Next))
  679.                     count++;
  680.                 break;
  681.  
  682.             case muKeyType_gid:
  683.                 while ((def->gid != info->Pub.gid) && (def = def->Next))
  684.                     count++;
  685.                 break;
  686.  
  687.             case muKeyType_GroupName:
  688.                 while (stricmp(def->GroupName, info->Pub.GroupName) && (def = def->Next))
  689.                     count++;
  690.                 break;
  691.  
  692.             case muKeyType_WGroupID:
  693.                 FreeV(info->Pattern);
  694.                 len = 2*strlen(info->Pub.GroupID)+2;
  695.                 if ((info->Pattern = MAllocV(len)) &&
  696.                      (ParsePatternNoCase(info->Pub.GroupID, info->Pattern, len) != -1))
  697.                     while (!MatchPatternNoCase(info->Pattern, def->GroupID) && (def = def->Next))
  698.                         count++;
  699.                 else {
  700.                     FreeV(info->Pattern);
  701.                     info->Pattern = NULL;
  702.                     def = NULL;
  703.                 }
  704.                 break;
  705.  
  706.             case muKeyType_WGroupIDNext:
  707.                 if (info->Pattern) {
  708.                     while ((count <= info->Count) && (def = def->Next))
  709.                         count++;
  710.                     if (def)
  711.                         while (!MatchPatternNoCase(info->Pattern, def->GroupID) && (def = def->Next))
  712.                             count++;
  713.                 } else
  714.                     def = NULL;
  715.                 break;
  716.  
  717.             case muKeyType_WGroupName:
  718.                 FreeV(info->Pattern);
  719.                 len = 2*strlen(info->Pub.GroupName)+2;
  720.                 if ((info->Pattern = MAllocV(len)) &&
  721.                      (ParsePatternNoCase(info->Pub.GroupName, info->Pattern, len) != -1))
  722.                     while (!MatchPatternNoCase(info->Pattern, def->GroupName) && (def = def->Next))
  723.                         count++;
  724.                 else {
  725.                     FreeV(info->Pattern);
  726.                     info->Pattern = NULL;
  727.                     def = NULL;
  728.                 }
  729.                 break;
  730.  
  731.             case muKeyType_WGroupNameNext:
  732.                 if (info->Pattern) {
  733.                     while ((count <= info->Count) && (def = def->Next))
  734.                         count++;
  735.                     if (def)
  736.                         while (!MatchPatternNoCase(info->Pattern, def->GroupName) && (def = def->Next))
  737.                             count++;
  738.                 } else
  739.                     def = NULL;
  740.                 break;
  741.  
  742.             case muKeyType_MgrUid:
  743.                 while ((def->MgrUid != info->Pub.MgrUid) && (def = def->Next))
  744.                     count++;
  745.                 break;
  746.  
  747.             case muKeyType_MgrUidNext:
  748.                 while ((count <= info->Count) && (def = def->Next))
  749.                     count++;
  750.                 if (def)
  751.                     while ((def->MgrUid != info->Pub.MgrUid) && (def = def->Next))
  752.                         count++;
  753.                 break;
  754.  
  755.             default:
  756.                 def = NULL;
  757.                 break;
  758.         }
  759.         if (def) {
  760.             FillGroupInfo(def, info);
  761.             info->Count = count;
  762.         } else
  763.             info = NULL;
  764.     } else
  765.         info = NULL;
  766.  
  767.     return(info);
  768. }
  769.  
  770.  
  771.     /*
  772.      *        Fill in the Group Information
  773.      */
  774.  
  775. static void FillGroupInfo(struct muGroupDef *def, struct muPrivGroupInfo *info)
  776. {
  777.     strncpy(info->Pub.GroupID, def->GroupID, muGROUPIDSIZE-1);
  778.     info->Pub.GroupID[muGROUPIDSIZE-1] = '\0';
  779.     info->Pub.gid = def->gid;
  780.     info->Pub.MgrUid = def->MgrUid;
  781.     strncpy(info->Pub.GroupName, def->GroupName, muGROUPNAMESIZE-1);
  782.     info->Pub.GroupName[muGROUPNAMESIZE-1] = '\0';
  783. }
  784.